package org.fioma.tree.suffixTree.memory;

import java.io.BufferedWriter;
import java.io.IOException;

import org.fioma.general.Tools;
import org.fioma.tree.Path;
import org.fioma.tree.bytes.LabelRefBytesIndex;

public abstract class SimpleInternalSuffixNodeMemory<I extends InternalSuffixNodeMemory<I, F, N>, F extends LeafSuffixNodeMemory<I, F, N>, N extends SuffixNodeMemory<I, F, N>>
		extends SimpleSuffixNodeMemory<I, F, N> implements InternalSuffixNodeMemory<I, F, N> {

	// @Override
	// public I createChildInternalNode(LabelRefBytesIndex word) {
	// I ret = nodeMemoryFactory.getInternalNode(memory
	// .allocMemoryInternalNode());
	// ret.setLabel(word);
	// ret.setParent((I) this);
	// return ret;
	// }
	//
	// @Override
	// public F createChildLeaf(L word) {
	// F ret = nodeMemoryFactory.getLeafNode(memory.allocMemoryLeafNode());
	// ret.setLabel(word);
	// ret.setParent((I) this);
	// return ret;
	// }

	// @Override
	// public SuffixNodeMemory<L, I, F> getChild(byte letter) {
	// long childAddress = memory.getChildAddress(pos, letter);
	// SuffixNodeMemory<L, I, F> ret;
	// if (memory.isLeaf(childAddress)) {
	// ret = nodeMemoryFactory.getLeafNode(childAddress);
	// } else {
	// ret = nodeMemoryFactory.getInternalNode(childAddress);
	// }
	// return ret;
	// }
	//
	public SimpleInternalSuffixNodeMemory(long pos, SuffixTreeHandlerMemory<I, F, N> treeHandler) {
		super(pos, treeHandler);
	}

	@Override
	public void setChild(N node, byte letter) {
		this.getTreeHandler().getMemory().setChildAddress(getPos(), letter, node.getPos());
	}

	@Override
	public N[] getChilds() {
		long[] childsAddresses = this.getTreeHandler().getMemory().getChildsAddresses(getPos());
		int length = childsAddresses.length;
		N[] ret = this.getTreeHandler().createChildrenNodes();
		long childAddress;
		for (int i = 0; i < length; i++) {
			childAddress = childsAddresses[i];
			if (this.getTreeHandler().getMemory().isLeaf(childAddress)) {
				ret[i] = (N) this.getTreeHandler().createLeafNode(childAddress);
			} else {
				ret[i] = (N) this.getTreeHandler().createInternalNode(childAddress);
			}
		}
		return ret;
	}

	@Override
	public boolean isLeaf() {
		return false;
	}

	@Override
	public N nextNode(char letter) {
		return nextNode(Tools.transformToByte(letter));
	}

	@Override
	public N nextNode(byte letter) {
		return getChild(letter);
	}

	public N getChild(byte letter) {
		long childAddress = this.getTreeHandler().getMemory().getChildAddress(getPos(), letter);
		if (this.getTreeHandler().getMemory().isLeaf(childAddress)) {
			return (N) this.getTreeHandler().createLeafNode(childAddress);
		} else {
			return (N) this.getTreeHandler().createInternalNode(childAddress);
		}
	}

	@Override
	public void setChild(N node, char letter) {
		setChild(node, Tools.transformToByte(letter));
	}

	// @Override
	// public I getOrCreateInternalNode(LabelRefBytesIndex word) {
	// return treeHandler.getOrCreateInternalNode((I) this, word);
	// }

	@Override
	public F addWord(LabelRefBytesIndex word) {
		return treeHandler.addWord((I) this, word);
	}

	@Override
	public void printWords(BufferedWriter bw, String prefix) throws IOException {
		treeHandler.printWords((I) this, bw, prefix);
	}

	@Override
	public boolean find(LabelRefBytesIndex word) {
		return treeHandler.find((I) this, word);
	}

	@Override
	public I createChildInternalNode(LabelRefBytesIndex label) {
		return treeHandler.createChildInternalNode((I) this, label);
	}

	@Override
	public F createChildLeaf(LabelRefBytesIndex label) {
		return treeHandler.createChildLeaf((I) this, label);
	}

	@Override
	public I getOrCreateInternalNode(LabelRefBytesIndex label) {
		return treeHandler.getOrCreateInternalNode((I) this, label);
	}

	@Override
	public Path<N> getLongestPath() {
		Path<N> ret = null;
		int maxLength = 0;

		N[] nodes = getChilds();
		for (N node : nodes) {
			if (node != null) {
				Path<N> nodeLongestPath = node.getLongestPath();
				nodeLongestPath.addNode(node);
				if (nodeLongestPath.getLabelLength() > maxLength) {
					maxLength = nodeLongestPath.getLabelLength();
					ret = nodeLongestPath;
				}
			}
		}
		return ret;
	}

}
